package com.alibaba.algo.apiimpl.user;

import com.alibaba.algo.apiimpl.policy.SysPolicyServiceImpl;
import com.alibaba.algo.constants.Constants;
import com.alibaba.algo.cooperation.common.BaseResult;
import com.alibaba.algo.cooperation.usercomponent.service.user.SysRoleResourceActionService;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.SelectResourceActionListByRoleReqVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.SelectResourceListByRoleReqVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.UpdateRoleResourceActionVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.UpdateRoleResourceVO;
import com.alibaba.algo.cooperation.usercomponent.vo.res.user.*;
import com.alibaba.algo.dao.user.SysRoleMapper;
import com.alibaba.algo.domain.user.SysResourceDomain;
import com.alibaba.algo.domain.user.SysRoleResourceActionDomain;
import com.alibaba.algo.domain.user.SysRoleResourceDomain;
import com.alibaba.algo.dtos.user.SysResourceTreeNodeDTO;
import com.alibaba.algo.entity.user.SysResource;
import com.alibaba.algo.entity.user.SysRoleResourceAction;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 类SysResourceServiceImpl.java的实现描述：资源 serviceimpl
 *
 * @author nieganggang 2021-03-12 16:08:17
 */
@Slf4j
@RestController
public class SysRoleResourceActionServiceImpl implements SysRoleResourceActionService {

    @Autowired
    private SysRoleResourceActionDomain sysRoleResourceActionDomain;

    @Autowired
    private SysRoleResourceDomain sysRoleResourceDomain;

    @Autowired
    private SysResourceDomain sysResourceDomain;

    @Resource
    private SysRoleMapper sysRoleMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public BaseResult updateResourceActionListByRole(String roleCode,String appCode,String resourceIds,HashMap<Long, ResourceActionInfo> newResourceActionMap) {
        //删除角色现有资源动作组
        UpdateRoleResourceActionVO deleteVO = new UpdateRoleResourceActionVO(roleCode,-1,"",appCode);
        sysRoleResourceActionDomain.deleteListByRole(deleteVO);
        //删除角色现有资源组
        UpdateRoleResourceVO resourceDeleteVO = new UpdateRoleResourceVO(roleCode,appCode);
        sysRoleResourceDomain.deleteListByRole(resourceDeleteVO);
        //写入更新后的资源列表
        List<Long> resourceIdList = new ArrayList<>();
        if(StringUtils.isNotEmpty(resourceIds)){
            resourceIdList = Stream.of(resourceIds.split(",")).map(Long::valueOf).collect(Collectors.toList());
        }
        Long roleId = sysRoleMapper.selectRoleIdByCode(roleCode,appCode);
        if(!ObjectUtils.isEmpty(resourceIdList) && null != roleId && roleId >= 0 && StringUtils.isNotEmpty(appCode)){
            sysRoleResourceDomain.batchInsert(roleId,resourceIdList);
        }
        //逐条插入更新后的资源动作组
        for (Map.Entry<Long, ResourceActionInfo> entry : newResourceActionMap.entrySet()) {
            long resourceId = entry.getKey();
            List<ActionInfo> actionInfoList = entry.getValue().getActionList();
            for(ActionInfo info : actionInfoList){
                String actionCode = info.getActionCode();
                UpdateRoleResourceActionVO vo = new UpdateRoleResourceActionVO(roleCode,resourceId,actionCode,appCode);
                insert(vo);
            }
        }
        return BaseResult.buildSuccess("Successfully updated resourceAction List.");
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public BaseResult insert(UpdateRoleResourceActionVO vo) {
        Long roleId = sysRoleResourceActionDomain.selectRoleIdByCode(vo);
        Long resourceActionId = sysRoleResourceActionDomain.selectResourceActionIdByResourceIdActionCode(vo);
        SysRoleResourceAction sysRoleResourceAction=new SysRoleResourceAction();
        sysRoleResourceAction.setRoleId(roleId);
        sysRoleResourceAction.setResourceActionId(resourceActionId);
        sysRoleResourceAction.setAppCode(vo.getAppCode());
        if(null == roleId || null == resourceActionId || StringUtils.isEmpty(vo.getAppCode())){
           log.error("SysRoleResourceActionService insert,roleId or resourceActionId or appCode is null.");
            return BaseResult.buildError("insert roleId or resourceActionId or appCode is null");
        }
        int result = sysRoleResourceActionDomain.insert(sysRoleResourceAction);
        return BaseResult.buildSuccess(result);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public BaseResult delete(UpdateRoleResourceActionVO vo) {
        int result=sysRoleResourceActionDomain.delete(vo);
        return BaseResult.buildSuccess(result);
    }



    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public BaseResult selectResourceActionTree(String appCode) {
        //获取该应用全量资源
        List<ResourceInfo> resourceList = sysRoleResourceActionDomain.selectResourceListAll(appCode);
        Map<Long,SysResource> treeMap = new HashMap<>();
        //1. 初始化，将所有资源节点置入treeMap中，其资源动作组和子节点列表置为空
        for(ResourceInfo info : resourceList){
            long resourceId = info.getResourceId();
            if(!treeMap.containsKey(resourceId)){
                SysResource res = new SysResource();
                res.setResourceId(resourceId);
                res.setResourceCode(info.getResourceCode());
                res.setResourceName(info.getResourceName());
                treeMap.put(resourceId,res);
            }
        }
        //2. 将所有资源节点的父子关系链接完毕（建资源树），将根节点作为返回值
        SysResource result = new SysResource();
        for(ResourceInfo info : resourceList){
            long resourceId = info.getResourceId();
            long myParentId = info.getParentId();
            SysResource tmpResource = treeMap.get(resourceId);
            //根节点的父节点id为-1，不用做链接处理，直接存为返回值
            if(myParentId == -1){
                result = tmpResource;
            }else{//链接当前节点和它的父节点
                SysResource parentResource=treeMap.get(myParentId);
                parentResource.addChild(tmpResource);
            }
        }
        //3. 将所有资源节点与动作的关系链接完毕（动作列表）
        //获取该应用全量资源动作组
        List<SelectResourceActionListVO> resourceActionList = sysRoleResourceActionDomain.selectResourceActionListAll(appCode);
        for(SelectResourceActionListVO vo : resourceActionList){
            long resourceId = vo.getResourceId();
            SysResource tmpResource = treeMap.get(resourceId);
            if(!ObjectUtils.isEmpty(tmpResource)){
                ActionInfo info = new ActionInfo(vo.getActionId(), vo.getActionCode(), vo.getActionName());;
                tmpResource.addAction(info);
            }
        }
        //4. 返回根节点
        return BaseResult.buildSuccess(result);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public BaseResult selectResourceActionListByRole(SelectResourceActionListByRoleReqVO vo) {
        SelectResourceListAndActionListVO result = new SelectResourceListAndActionListVO();
        //查询资源动作列表
        List<SelectResourceActionListVO> resourceActionList = sysRoleResourceActionDomain.selectResourceActionListByRoleReq(vo);
        Map<Long,ResourceActionInfo> map = new HashMap<>();
        for(SelectResourceActionListVO tmpVo : resourceActionList){
            long tmpId = tmpVo.getResourceId();
            if(!map.containsKey(tmpId)){
                ResourceActionInfo resourceActionInfo= new ResourceActionInfo(
                        tmpVo.getResourceId(),
                        tmpVo.getResourceCode(),
                        tmpVo.getResourceName(),
                        tmpVo.getParentId()
                        );
                map.put(tmpId,resourceActionInfo);
            }
            ResourceActionInfo tmpInfo = map.get(tmpId);
            tmpInfo.addAction(new ActionInfo(
                    tmpVo.getActionId(),
                    tmpVo.getActionCode(),
                    tmpVo.getActionName()
            ));
        }
        //查询资源列表
        Long roleId = sysRoleMapper.selectRoleIdByCode(vo.getRoleCode(),vo.getAppCode());
        //只根据roleId来查询，roleId通过roleCode、appCode查询
        List<SysResourceTreeNodeDTO> resourceNodeList = sysRoleResourceDomain.selectResourceListByRoleIdAndAppCode(roleId);
        Set<SysResource> sysResourceSet = new HashSet<>();
        if(!ObjectUtils.isEmpty(resourceNodeList)){
            for(SysResourceTreeNodeDTO sysResourceTreeNodeDTO : resourceNodeList){
                List<SysResource> sysResourceList = sysResourceDomain.selectResourceIdListRecursiveToRoot(sysResourceTreeNodeDTO.getId());
                sysResourceSet.addAll(sysResourceList);
            }
        }
        List<ResourceInfo> resourceList = new ArrayList<>();
        sysResourceSet.stream().forEach(item -> {
            ResourceInfo resourceInfo = new ResourceInfo();
            BeanUtils.copyProperties(item,resourceInfo);
            resourceInfo.setResourceId(item.getId());
            resourceList.add(resourceInfo);
        });
        result.setResourceList(resourceList);
        //将资源列表中有但动作列表中没有的数据补充在动作map中
        for(ResourceInfo resource : resourceList){
            if(!map.containsKey(resource.getResourceId())){
                ResourceActionInfo resourceActionInfo= new ResourceActionInfo(
                        resource.getResourceId(),
                        resource.getResourceCode(),
                        resource.getResourceName(),
                        resource.getParentId()
                );
                map.put(resource.getResourceId(),resourceActionInfo);
            }
        }
        result.setActionMap(map);
        return BaseResult.buildSuccess(result);
    }

    @Override
    public BaseResult selectResourceListByRole(@RequestBody SelectResourceListByRoleReqVO vo){
        ResourceListVO resourceListVO = new ResourceListVO();
        List<SysResourceTreeNodeDTO> resourceNodeList = sysRoleResourceDomain.selectResourceListByRoleIdListAndAppCode(vo);
        Set<SysResource> sysResourceSet = new HashSet<>();
        if(!ObjectUtils.isEmpty(resourceNodeList)){
            for(SysResourceTreeNodeDTO sysResourceTreeNodeDTO : resourceNodeList){
                List<SysResource> sysResourceList = sysResourceDomain.selectResourceIdListRecursiveToRoot(sysResourceTreeNodeDTO.getId());
                sysResourceSet.addAll(sysResourceList);
            }
        }
        List<ResourceInfo> resourceList = new ArrayList<>();
        sysResourceSet.stream().forEach(item -> {
            ResourceInfo resourceInfo = new ResourceInfo();
            BeanUtils.copyProperties(item,resourceInfo);
            resourceInfo.setResourceId(item.getId());
            resourceList.add(resourceInfo);
        });
        // 增加排序
        resourceList.sort(new Comparator<ResourceInfo>() {
            @Override
            public int compare(ResourceInfo o1, ResourceInfo o2) {
                if(null!=o1.getSort() && null!=o2.getSort()){
                    return o1.getSort().intValue()-o2.getSort().intValue();
                }else{
                    return 0;
                }
            }
        });
        //过滤岗位管理(岗位管理下无子节点则不展示岗位管理节点)
        if(!ObjectUtils.isEmpty(resourceList)){
            AtomicReference<Long> posRootResouceId = new AtomicReference<>();
            AtomicBoolean posRootDisableFlag = new AtomicBoolean(true);
            resourceList.forEach(item -> {
                if(Constants.POS_ROOT_RESOUCE_NAME.equals(item.getResourceName())){
                    posRootResouceId.set(item.getResourceId());
                }
            });
            if(null != posRootResouceId.get()){
                resourceList.forEach(item -> {
                    if(null != posRootResouceId && posRootResouceId.get().equals(item.getParentId())){
                        posRootDisableFlag.set(false);
                    }
                });
            }
            resourceList.removeIf(item -> (
                    posRootDisableFlag.get() & (null != posRootResouceId && null != posRootResouceId.get() && posRootResouceId.get().equals(item.getResourceId()))
            ));
        }
        resourceListVO.setResourceList(resourceList);
        return BaseResult.buildSuccess(resourceListVO);
    }
}